package net.beyondts.mplug;

import net.beyondts.mplug.utils.BeanFactory;
import net.beyondts.mplug.utils.IOUtils;
import net.beyondts.mplug.utils.MethodUtils;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

/**
 * Project: mplug-project<br/>
 * Description: A base extension handler which will handle those extensions defined in "extensions" and "extensions.default" files<br/>
 * Created at: 2019-1-13<br/>
 * Owned by beyondts.
 *
 * @author blazecrystal
 * @version 1.0.0
 */
public class ConfigurableExtensionHandler extends AbstractExtensionHandler {
    private static Logger LOGGER = LoggerFactory.getLogger(ConfigurableExtensionHandler.class);

    private String pluginsDir;
    private List<String> extensions;

    public ConfigurableExtensionHandler() throws IOException {
        this.pluginsDir = PluginsUtils.getPluginsDir();
        extensions = new ArrayList<>();
        load();
    }

    private void load() throws IOException {
        InputStream is = null;
        try {
            is = ClassLoader.getSystemResourceAsStream("plugins/config/extensions.default");
            load(is);
        } finally {
            IOUtils.closeQuietly(is);
        }
        try {
            is = new FileInputStream(pluginsDir + "config" + File.separator + "extensions");
            load(is);
        } finally {
            IOUtils.closeQuietly(is);
        }
    }

    private void load(InputStream is) throws IOException {
        BufferedReader br = null;
        br = new BufferedReader(new InputStreamReader(is, "UTF-8"));
        String line = null;
        while((line = br.readLine()) != null) {
            line = line.trim();
            if (StringUtils.isNotBlank(line) && !extensions.contains(line)) {
                extensions.add(line);
            }
        }
    }

    /**
     * this method should be override. and in sub-class, the new method should use super.handle(joinPoint) to handle
     * extension, and should add an annotation @Around("within(basePackageForExtension..*)"). for example:
     * @Aspect
     * public class SomeExtensionHandler extends ConfigurableExtensionHandler {
     *     public SomeExtensionHandler(@Value("#{systemProperties['plugins.dir']}") String pluginsDir) throws IOException {
     *         super(pluginsDir);
     *     }
     *
     *     @Around("within(basePackageForExtension..*)")
     *     public Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
     *         return super.handle(joinPoint);
     *     }
     * }
     * @param joinPoint
     * @return
     * @throws Throwable
     */
    protected Object handle(ProceedingJoinPoint joinPoint) throws Throwable {
        String signature = joinPoint.getSignature().toString();
        if (extensions.contains(signature)) {
            try {
                return invokePluginMethod(joinPoint, signature);
            } catch (PluginInvocationException e) {
                return invokeExtensionMethod(joinPoint, signature);
            }
        }
        return invokeExtensionMethod(joinPoint, signature);
    }
}
